package com.youlu.campus.service.pay;

import cn.hutool.core.io.FileUtil;
import cn.hutool.http.ContentType;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.wechat.pay.contrib.apache.httpclient.SignatureExec;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.wechat.pay.contrib.apache.httpclient.util.RsaCryptoUtil;
import com.youlu.campus.service.config.WxPayConfig;
import com.youlu.campus.service.pay.wxpay.kit.PayKit;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.util.SignUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.crypto.BadPaddingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.*;

@Slf4j
@Service
public class PayV3Service {


    @Autowired
    private WxPayConfig wxPayConfig;

    private static String mchId = "1606927438"; // 商户号
    private static String mchSerialNo = "3BAFFBA782C64D07F21072234E01F31138844466"; // 商户证书序列号
    private static String appId = "";

    // 你的商户私钥
    private static String privateKey = "qazwsxedcrfvtgbyhnujmikolp098765";

    // 你的微信支付平台证书
    private static String certificate =  "-----BEGIN CERTIFICATE-----\n" +
            "MIID9jCCAt6gAwIBAgIUO6/7p4LGTQfyEHIjTgHzETiERGYwDQYJKoZIhvcNAQEL\n" +
            "BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\n" +
            "FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg\n" +
            "Q0EwHhcNMjEwODAzMDczNzI4WhcNMjYwODAyMDczNzI4WjCBhzETMBEGA1UEAwwK\n" +
            "MTYwNjkyNzQzODEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTMwMQYDVQQL\n" +
            "DCrlm73pmYXot6/muLjvvIjljJfkuqzvvInnp5HmioDmnInpmZDlhazlj7gxCzAJ\n" +
            "BgNVBAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQAD\n" +
            "ggEPADCCAQoCggEBAJ4uGCamDyY7iodZeI9AuNJ5XEBGJdFqeV9MhMV5tQVIx5Nb\n" +
            "q1bMHWn7Q5D8FzYM7qzOrrQZQ43SGTr6SfTbNk0F5oZR6ZGNLu8uDgV6oHYN8VC7\n" +
            "Y+aZ6BI1E04BuuZ0gDW79JyKVv/8v5PmwneIhhQxWg+7+bwE0WTM6b7rjazXZD0o\n" +
            "LltpjFs9dePwBreladMOO1JWOh+/OwI+qATUeWkkrPBTtqzQ6Rhkd85y+gYQVK+E\n" +
            "rOSEyAwxPWtWlLTJNPCD1E2f5Lz7IzDk/zvt3EH/6xeEMq+Cjtp62nQVqyee3QOb\n" +
            "K8e1/3aGR4bpOYKsHXL2RPdWTjwaT6Ph0AR4P/MCAwEAAaOBgTB/MAkGA1UdEwQC\n" +
            "MAAwCwYDVR0PBAQDAgTwMGUGA1UdHwReMFwwWqBYoFaGVGh0dHA6Ly9ldmNhLml0\n" +
            "cnVzLmNvbS5jbi9wdWJsaWMvaXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2\n" +
            "QUQzOTc1NDk4NDZDMDFDM0U4RUJEMjANBgkqhkiG9w0BAQsFAAOCAQEAMOGoOIhd\n" +
            "MtfuwKIW58lJ7GAtNVfmnj4ucG5tphRwAqe7zPFONHic31PHtB1o5FFGjiBLQ0sX\n" +
            "RI/dovi7n1XvJaed+EgID5KI8Fue8P1A3cNs1TbHgZzGUfuiNsCLwW0L/vhj8SJ1\n" +
            "MMrQ0pb4GqKBjePOK9kT/YFZfbtjBz8zZ5xQquV2Vv24eHZREgIu+kyC39f7B/dd\n" +
            "CSr3a9txJmmWWHv/MQUJSxfWBr83dNCsdKjWCZO2+jlIFiQNVZW704vP0oFuW76i\n" +
            "+t8boJkpE30WAqBjetPp8366978wi/qmALd8tfjmOcYYUlroxzpOPXJvIE/mVVv9\n" +
            "V2cz6idmQ6/DJA==\n" +
            "-----END CERTIFICATE-----";

    private String unifiedOrderPayUrl= "https://api.mch.weixin.qq.com/v3/pay/transactions/h5";

    private static final String VERSION = System.getProperty("java.version");
    private static final String OS = System.getProperty("os.name") + "/" + System.getProperty("os.version");


    private CloseableHttpClient init() throws UnsupportedEncodingException, FileNotFoundException {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream("/data/cert/apiclient_key.pem"));
        X509Certificate wechatpayCertificate = PemUtil.loadCertificate(new FileInputStream("/data/cert" +
                "/wechatpay_11B3033F05B16EDE0FE829F2F7D8D2AFBB51AC2E.pem"));
        ArrayList<X509Certificate> listCertificates = new ArrayList<>();
        listCertificates.add(wechatpayCertificate);

        CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
                .withWechatpay(listCertificates)
                .build();
        return httpClient;
    }

    public Map<String, String> v3Notify(HttpServletRequest request, HttpServletResponse response){
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String serialNo = request.getHeader("Wechatpay-Serial");
        String signature = request.getHeader("Wechatpay-Signature");

        String notifyResult = readData(request);
        log.info("支付通知密文 {}", notifyResult);
        Map<String, String> map = new HashMap<>(3);
        try {
            String ciphertext = RsaCryptoUtil.decryptOAEP(notifyResult, PemUtil.loadPrivateKey(new FileInputStream("/data/cert/apiclient_key.pem")));
            log.info("支付通知明文 {}", ciphertext);
            if(StringUtils.isBlank(ciphertext)){
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }else{
                response.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
            return map;
        } catch (BadPaddingException e) {
            e.printStackTrace();
            log.error("【支付通知】->{}",e);
            map.put("code", "ERROR");
            map.put("message", "签名错误");
            return map;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            log.error("【支付通知】->{}",e);
            map.put("code", "ERROR");
            map.put("message", "私钥文件找不到");
            return map;
        }catch (Exception e) {
            e.printStackTrace();
            log.error("【支付通知】->{}",e);
            map.put("code", "ERROR");
            map.put("message", "其他错误");
            return map;
        }


    }

    public static String readData(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line; (line = br.readLine()) != null; ) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void pay(){
        CloseableHttpClient httpClient = null;
        try {
             httpClient = init();
            HttpPost httpPost = new HttpPost(unifiedOrderPayUrl);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type","application/json; charset=utf-8");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();

            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("mchid",mchId)
                    .put("appid", "wxd851ccee6eb72932")
                    .put("description", "测试-H5下单")
                    .put("notify_url", wxPayConfig.getPayWechatNotifyUrl())
                    .put("out_trade_no", System.currentTimeMillis()+"");
            rootNode.putObject("amount")
                    .put("currency", "CNY")
                    .put("total", 1);
//            rootNode.putObject("payer")
//                    .put("openid", "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o");
            rootNode.putObject("scene_info")
                    .put("payer_client_ip", "127.0.0.1")
                    .putObject("h5_info")
                    .put("type","Wap");



            //rootNode.
           // rootNode.put("sign", SignUtils.createHmacSha256Sign())
            objectMapper.writeValue(bos, rootNode);
//            String authType = "WECHATPAY2-SHA256-RSA2048";
//            String nonceStr = PayKit.generateStr();
//            // 构建签名参数
//            String authorization = buildAuthorization(RequestMethod.POST, "v3/pay/transactions/h5", mchId, mchSerialNo, "/data" +
//                    "/cert/apiclient_key.pem", objectMapper.writeValueAsString(rootNode), nonceStr, timestamp,
//                    authType);
//             log.info("【H5支付】 Authorization-> {} ",authorization);
//            httpPost.addHeader("Authorization",authorization);
//            httpPost.addHeader("Wechatpay-Serial",mchSerialNo);
//            String userAgent = String.format(
//                    "WeChatPay-gqgood-HttpClient/%s (%s) Java/%s",
//                    PayV3Service.class.getPackage().getImplementationVersion(),
//                    OS,
//                    VERSION == null ? "Unknown" : VERSION);
//            httpPost.addHeader("User-Agent", userAgent);
            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            Header[] allHeaders = httpPost.getAllHeaders();
            for(Header header : allHeaders){
                log.info(" 请求 header  {}",JSON.toJSONString(header));
            }
            CloseableHttpResponse response = httpClient.execute(httpPost);
            StatusLine statusLine = response.getStatusLine();
            String bodyAsString = EntityUtils.toString(response.getEntity());
            log.info("<<<<<<<<<【H5支付】预下单返回结果->{}",bodyAsString);
            log.info("<<<<<<<<<【H5支付】预下单返回状态->{}",JSON.toJSONString(statusLine));
            verifySignature(response,"");
            response.close();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(Objects.nonNull(httpClient)){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 验证签名
     *
     * @param response 接口请求返回的 {@link CloseableHttpResponse}
     * @param certPath 平台证书路径
     * @return 签名结果
     * @throws Exception 异常信息
     */
    public static boolean verifySignature(CloseableHttpResponse response, String certPath) throws Exception {
        Header[] allHeaders = response.getAllHeaders();
        for(Header header :allHeaders){
           log.info(" 响应header  {}",JSON.toJSONString(header));
        }
        //String timestamp = response.getHeader("Wechatpay-Timestamp");
       // String nonceStr = response.getHeader("Wechatpay-Nonce");
       // String signature = response.getHeader("Wechatpay-Signature");
        //String body = response.getBody();
        //return verifySignature(signature, body, nonceStr, timestamp, FileUtil.getInputStream(certPath));
        return true;
    }

    public static String buildAuthorization(RequestMethod method, String urlSuffix, String mchId,
                                            String serialNo, String keyPath, String body, String nonceStr,
                                            long timestamp, String authType) throws Exception {
        // 构建签名参数
        String buildSignMessage = PayKit.buildSignMessage(method, urlSuffix, timestamp, nonceStr, body);
        String signature = PayKit.createSign(buildSignMessage, keyPath);
        // 根据平台规则生成请求头 authorization
        return PayKit.getAuthorization(mchId, serialNo, nonceStr, String.valueOf(timestamp), signature, authType);
    }

    /**
     * 私钥签名
     */
    public String sign(String sign6) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException,
            FileNotFoundException {
        PrivateKey privateKey =  PemUtil.loadPrivateKey(new FileInputStream("/data/cert/apiclient_key.pem"));

        Signature sign = Signature.getInstance("SHA256withRSA");

        sign.initSign(privateKey);

        sign.update(sign6.getBytes(StandardCharsets.UTF_8));

        return Base64.getEncoder().encodeToString(sign.sign());
    }

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();

        ObjectNode rootNode = objectMapper.createObjectNode();
        rootNode.put("mchid",mchId)
                .put("appid", "wxd851ccee6eb72932")
                .put("description", "测试")
                .put("notify_url", "")
                .put("out_trade_no", System.currentTimeMillis()+"");
        rootNode.putObject("amount")
                .put("currency", "CNY")
                .put("total", 1);
//            rootNode.putObject("payer")
//                    .put("userId", "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o");
        rootNode.putObject("scene_info")
                .put("payer_client_ip", "127.0.0.1")
                .putObject("h5_info")
                .put("type","Wap");
        System.out.println(JSON.toJSONString(objectMapper.writeValueAsString(rootNode)));



    }

}
